package drds.server.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import drds.server.config.ErrorCode;
import drds.server.datasource.IConnectionHolder;
import drds.server.route.RouteNode;
import drds.server.server.Session;

/**
 * 
 */
public class RollbackNodeHandler extends MultiNodeHandler {
	private static final Logger LOGGER = LoggerFactory.getLogger(RollbackNodeHandler.class);

	public RollbackNodeHandler(Session session) {
		super(session);
	}

	/**
	 * 只支持单库回滚
	 */
	public void rollback() {
		final int nodeSize = session.getNodeSize();
		lock.lock();
		try {
			reset(nodeSize);
		} finally {
			lock.unlock();
		}
		if (session.closed()) {
			decrementCountToZero();
			return;
		}

		// 执行
		int count = 0;
		for (final RouteNode node : session.getNodeSet()) {
			if (node == null) {
				LOGGER.error("null is contained in RoutResultsetNodes, source = " + session.getSessionContext());
				continue;
			}
			final IConnectionHolder connectionHolder = session.getConnectionHolder(node);

			if (connectionHolder != null) {
				boolean isClosed = connectionHolder.isClosedOrQuit();
				if (isClosed) {
					session.getSessionContext().writeErrorMessage(ErrorCode.ER_UNKNOWN_ERROR, "receive rollback,but find backend con is closed or quit");
					LOGGER.error(connectionHolder + "receive rollback,but fond backend con is closed or quit");
					return;
				}
				if (clearIfSessionClosed(session)) {
					return;
				}
				connectionHolder.setHandler(RollbackNodeHandler.this);
				//
				connectionHolder.rollback();

				++count;
			}
		}

		if (count < nodeSize && decrementCountBy(nodeSize - count)) {
			/**
			 * assumption: only caused by front-end connection close. <br/>
			 * Otherwise, packet must be returned to front-end
			 */
			session.clearResources(true);
		}
	}

	@Override
	public void okResponse(IConnectionHolder connectionHolder, byte[] okBytes) {
		if (decrementCountBy(1)) {
			// clear all resources
			session.clearResources(false);
			if (this.isFail() || session.closed()) {
				tryErrorFinished(true);
			} else {
				session.getSessionContext().write(okBytes);
			}
		}
	}

	@Override
	public void terminate(Runnable runnable) {

	}

}
